package com.zeus.core.context;

import com.zeus.common.constants.ZeusConfigConstant;
import com.zeus.common.constants.ZeusConstant;
import com.zeus.common.enums.ZeusAlarmLevelEnum;
import com.zeus.common.enums.ZeusAlarmModelEnum;
import com.zeus.common.log.ZeusLoggerConfig;
import com.zeus.common.utils.ProjectUtils;
import com.zeus.common.utils.ServerInfoUtils;
import com.zeus.core.config.data.ZeusConfig;
import com.zeus.core.factory.ZeusFactory;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

/**
 * 宙斯上下文
 *
 * @author f1ybear_wang  2022/2/22 10:18 下午
 */
public class ZeusContext {
    private final static Logger logger = LoggerFactory.getLogger(ZeusContext.class);

    /**
     * 是否已经初始化
     */
    private volatile static boolean inited = false;

    /**
     * 是否已经初始化
     */
    private static Context context;

    /**
     * 获取上下文
     * 
     * @return ZeusContext
     * @author f1ybear_wang  2022/2/22 11:02 下午
     */
    public static Context getContext() {
        try {
            if (inited) {
                if (context == null) {
                    context = new Context();
                }
            }
        } catch (Throwable e) {
            if (logger.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                logger.warn("### 宙斯上下文初始化失败:", e);
            }
        }
        return context;
    }

    /**
     * 初始化
     *
     * @author f1ybear_wang  2022/2/22 11:02 下午
     */
    public static void init() {
        // 如果第一次初始化失败，则会尝试第二次初始化
        for (int i = 0; i < 2; i++) {
            try {
                if (inited) {
                    return;
                }
                initContext();
                inited = true;
                return;
            } catch (Throwable e) {
                if (logger.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                    logger.warn("### 宙斯上下文初始化失败:", e);
                }
            }
        }
    }

    private static void initContext() {
        // 初始化
        context = new Context(ServerInfoUtils.getAppId(), ServerInfoUtils.getEnv(), ServerInfoUtils.getHostName(),
            ServerInfoUtils.getHostIp(), ProjectUtils.getDeployTag(), ZeusFactory.getZeusConfig());
    }

    @Getter
    public static class Context {

        /**
         * 应用名称
         */
        private String appId;

        /**
         * 环境
         */
        private String env;

        /**
         * 主机名称
         */
        private String hostName;

        /**
         * 主机IP
         */
        private String hostIp;

        /**
         * 部署tag
         */
        private String deployTag;

        /**
         * 报警配置
         */
        private ZeusConfig.ConfigData alarmConfig;

        public Context() {
            // default
            if (logger.isInfoEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                logger.info(">>> 宙斯准备初始化默认上下文");
            }
            this.alarmConfig = new ZeusConfig.DefaultConfigData();
            if (logger.isInfoEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                logger.info(">>> 宙斯初始化默认上下文完成");
            }
        }

        public Context(String appId, String env, String hostName, String hostIp, String deployTag,
            ZeusConfig zeusConfig) {
            if (logger.isInfoEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                logger.info(">>> 宙斯准备初始化上下文");
            }
            this.appId = appId;
            this.env = env;
            this.hostName = hostName;
            this.hostIp = hostIp;
            this.deployTag = deployTag;

            if (zeusConfig != null) {
                // 加载配置
                loadConfig(zeusConfig.getConfigData());

                // 注册监听
                registerListener(zeusConfig);
            }

            // 如果初始化失败，则使用默认配置
            if (this.alarmConfig == null) {
                this.alarmConfig = new ZeusConfig.DefaultConfigData();
            }
            if (logger.isInfoEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                logger.info(">>> 宙斯初始化上下文完成");
            }
        }

        private void registerListener(ZeusConfig zeusConfig) {
            if (zeusConfig == null) {
                return;
            }
            // 动态更新配置
            zeusConfig.addListener(e -> {
                if (logger.isInfoEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                    logger.info(">>> 宙斯上下文更新配置");
                }
                // 加载配置
                loadConfig(e);
            });
        }

        private void loadConfig(ZeusConfig.ConfigData configData) {
            if (configData == null) {
                return;
            }
            if (alarmConfig == null) {
                alarmConfig = new ZeusConfig.ConfigData();
            }
            this.alarmConfig.setBaseConfig(configData.getBaseConfig());
            this.alarmConfig.setSuperConfig(configData.getSuperConfig());
            this.alarmConfig.setAlarmLevelRuleList(configData.getAlarmLevelRuleList());
            this.alarmConfig.setRule2Threshold(configData.getRule2Threshold());

            ZeusConfig.BaseConfig baseConfig = configData.getBaseConfig();
            if (baseConfig != null) {
                final String applicationName = baseConfig.getApplicationName();
                final String profilesActive = baseConfig.getSpringProfilesActive();
                // 应用名称
                if (ZeusConstant.UNKNOWN.equalsIgnoreCase(this.appId) && applicationName != null
                    && !applicationName.isEmpty()) {
                    this.appId = applicationName;
                }
                // 环境
                if (ZeusConstant.UNKNOWN.equalsIgnoreCase(this.env) && profilesActive != null
                    && !profilesActive.isEmpty()) {
                    this.env = profilesActive;
                }
            }
        }

        public boolean isProduct() {
            return "pro".equals(env);
        }

        public boolean isYuFa() {
            return "yufa".equals(env);
        }

        public boolean isTest() {
            return "test".equals(env);
        }

        public boolean isTrunk() {
            return "trunk".equals(env);
        }

        public boolean isRelease() {
            return "release".equals(env);
        }

        /**
         * 监控是否开启
         *
         * @return true:开启 false:关闭
         */
        public boolean alarmEnable() {
            try {
                if (this.alarmConfig == null) {
                    return false;
                }

                // 超级配置不为空，则超级配置覆盖基础配置
                if (this.getSuperConfig() != null && this.getSuperConfig().getEnabled() != null) {
                    return this.getSuperConfig().getEnabled();
                }

                return this.getBaseConfig().getEnabled() != null && this.getBaseConfig().getEnabled();
            } catch (Throwable e) {
                if (logger.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                    logger.warn("### 宙斯获取开关配置出现异常 >> errMsg = {}", e.getMessage());
                }
            }
            return false;
        }

        /**
         * 获取模式
         * 
         * @return 模式
         * @author f1ybear_wang  2022/3/2 7:09 下午
         */
        public ZeusAlarmModelEnum alarmModel() {
            // 先判断超级配置是否有
            final ZeusConfig.SuperConfig superConfig = getSuperConfig();
            if (superConfig != null && superConfig.getModel() != null) {
                return superConfig.getModel();
            }

            // 标准配置
            ZeusConfig.BaseConfig baseConfig = getBaseConfig();
            if (baseConfig == null) {
                return ZeusAlarmModelEnum.NORMAL;
            }
            return Optional.ofNullable(baseConfig.getModel()).orElse(ZeusAlarmModelEnum.NORMAL);
        }

        /**
         * 校验报警内容是否可以忽略
         *
         * @param contentList 日志名称、class信息、堆栈信息
         * @return true:可以忽略，false:不可以忽略
         */
        public boolean checkAlarmContentIgnore(String... contentList) {
            try {
                if (contentList == null || contentList.length == 0) {
                    return true;
                }
                if (this.alarmConfig == null) {
                    return true;
                }

                // 黑名单
                Set<String> allBackList = new HashSet<>();

                // 超级配置 黑名单
                final ZeusConfig.SuperConfig superConfig = this.getSuperConfig();
                if (superConfig != null && superConfig.getBackList() != null && !superConfig.getBackList().isEmpty()) {
                    allBackList.addAll(superConfig.getBackList());
                }

                // 基础配置 黑名单
                final ZeusConfig.BaseConfig baseConfig = this.getBaseConfig();
                if (baseConfig != null && baseConfig.getBackList() != null && !baseConfig.getBackList().isEmpty()) {
                    allBackList.addAll(baseConfig.getBackList());
                }

                // 判断是否包含
                return Arrays.stream(contentList).filter(Objects::nonNull)
                    .anyMatch(e -> allBackList.stream().filter(Objects::nonNull).anyMatch(e::contains));
            } catch (Throwable e) {
                if (logger.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                    logger.warn("### 宙斯获取开关配置出现异常:", e);
                }
            }
            return false;
        }

        public ZeusConfig.BaseConfig getBaseConfig() {
            if (this.alarmConfig == null) {
                return null;
            }
            return this.alarmConfig.getBaseConfig();
        }

        public List<ZeusConfig.AlarmLevelRule> getLevelRule() {
            if (this.alarmConfig == null) {
                return new ArrayList<>();
            }
            return this.alarmConfig.getAlarmLevelRuleList();
        }

        public ZeusConfig.SuperConfig getSuperConfig() {
            if (this.alarmConfig == null) {
                return null;
            }
            return this.alarmConfig.getSuperConfig();
        }

        public List<ZeusConfig.DingTalkInfo> getBaseDingTalkList() {
            if (this.alarmConfig == null || this.alarmConfig.getBaseConfig() == null) {
                return new ArrayList<>();
            }
            final List<ZeusConfig.DingTalkInfo> dingTalkList = this.alarmConfig.getBaseConfig().getDingTalkList();
            if (dingTalkList == null || dingTalkList.isEmpty()) {
                return new ArrayList<>();
            }
            return dingTalkList;
        }

        public String getElkUrl() {
            final ZeusConfig.BaseConfig baseConfig = getBaseConfig();
            if (baseConfig == null) {
                return null;
            }
            return baseConfig.getElkUrl();
        }

        /**
         * 获取钉钉机器人列表根据等级编码
         *
         * @param levelCode 级别编码
         * @return 钉钉机器人列表
         * @author f1ybear_wang  2022/2/28 2:26 下午
         */
        public List<ZeusConfig.DingTalkInfo> getDingTalkList(String levelCode) {
            if (levelCode == null || levelCode.isEmpty()) {
                return new ArrayList<>();
            }
            List<ZeusConfig.AlarmLevelRule> levelRule = getLevelRule();
            if (levelRule == null || levelRule.isEmpty()) {
                return new ArrayList<>();
            }

            for (ZeusConfig.AlarmLevelRule alarmLevelRule : levelRule) {
                if (levelCode.equals(alarmLevelRule.getAlarmLevel())) {
                    return alarmLevelRule.getDingTalkList();
                }
            }
            return new ArrayList<>();
        }

        public ZeusConfig.Rule2Threshold getRule2Threshold() {
            if (this.alarmConfig == null || this.alarmConfig.getBaseConfig() == null) {
                return null;
            }
            return this.alarmConfig.getRule2Threshold();
        }

        public int getThresholdTime() {
            final ZeusConfig.Rule2Threshold rule2Threshold = getRule2Threshold();
            if (rule2Threshold == null) {
                return ZeusConfigConstant.DefaultValue.DEFAULT_RULE2_THRESHOLD_TIME;
            }
            return Optional.ofNullable(rule2Threshold.getTime())
                .orElse(ZeusConfigConstant.DefaultValue.DEFAULT_RULE2_THRESHOLD_TIME);
        }

        public int getThresholdNumber(ZeusAlarmLevelEnum level) {
            if (level == null) {
                return getThresholdNumber();
            }

            List<ZeusConfig.AlarmLevelRule> levelRules = getLevelRule();
            if (levelRules == null || levelRules.isEmpty()) {
                return level.getBaseNumber() * getThresholdNumber();
            }

            ZeusConfig.AlarmLevelRule alarmLevelRule = levelRules.stream()
                .filter(e -> level.getCode().equals(e.getAlarmLevel()) && e.getThresholdNumber() != null).findFirst()
                .orElse(null);
            if (alarmLevelRule != null) {
                return alarmLevelRule.getThresholdNumber();
            }
            return level.getBaseNumber() * getThresholdNumber();
        }

        public int getThresholdNumber() {
            ZeusConfig.Rule2Threshold rule2 = getRule2Threshold();
            if (rule2 == null || rule2.getNumber() == null) {
                return ZeusConfigConstant.DefaultValue.DEFAULT_RULE2_THRESHOLD_NUMBER;
            } else {
                return rule2.getNumber();
            }
        }

        public boolean startNotifyEnable() {
            final ZeusConfig.BaseConfig baseConfig = getBaseConfig();
            if (baseConfig == null) {
                return true;
            }
            return baseConfig.getStartNotifyEnable();
        }

        public boolean shutdownNotifyEnable() {
            final ZeusConfig.BaseConfig baseConfig = getBaseConfig();
            if (baseConfig == null) {
                return true;
            }
            return baseConfig.getShutdownNotifyEnabled();
        }

        public int getMessageLength() {
            ZeusConfig.BaseConfig baseConfig = getBaseConfig();
            if (baseConfig == null) {
                return ZeusConfigConstant.DefaultValue.DEFAULT_MESSAGE_LENGTH;
            }
            return Optional.ofNullable(baseConfig.getMessageLength())
                .orElse(ZeusConfigConstant.DefaultValue.DEFAULT_MESSAGE_LENGTH);
        }

        public int getExceptionMessageLength() {
            ZeusConfig.BaseConfig baseConfig = getBaseConfig();
            if (baseConfig == null) {
                return ZeusConfigConstant.DefaultValue.DEFAULT_EXCEPTION_LENGTH;
            }
            return Optional.ofNullable(baseConfig.getExceptionLength())
                .orElse(ZeusConfigConstant.DefaultValue.DEFAULT_EXCEPTION_LENGTH);
        }

        public int getStackTraceLength() {
            ZeusConfig.BaseConfig baseConfig = getBaseConfig();
            if (baseConfig == null) {
                return ZeusConfigConstant.DefaultValue.DEFAULT_STACK_LENGTH;
            }
            return Optional.ofNullable(baseConfig.getStackLength())
                .orElse(ZeusConfigConstant.DefaultValue.DEFAULT_STACK_LENGTH);
        }
    }

}
